package common;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class WordHistogram {
  private HashMap wordMap;
  
  private class HistoWord implements Comparable {
    public String text;
    public Integer count;
    
    public HistoWord(String wordText, Integer count) {
      this.text = wordText;
      this.count = count;
    }
    
    public int compareTo(Object obj) {
      if(obj instanceof HistoWord) {
        return compareTo((HistoWord)obj);
      }
      else
        throw new ClassCastException("Cannot compare "+obj.getClass().getName() + " to a HistoWord");
    }
    
    public int compareTo(HistoWord word) {
      return this.count.compareTo(word.count);
    } 
  }
  
  public WordHistogram(char[] breakChars, StopWordFile stopWordFile, File fileToCount) 
  throws FileNotFoundException, IOException {
    wordMap = new HashMap();
    BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(fileToCount));
    IndexWordUtil wordUtil = new IndexWordUtil(breakChars);
    for (String word = wordUtil.getNextWord(inputStream); word != null; word = wordUtil.getNextWord(inputStream)) {
      if (!stopWordFile.isStopWord(word)) {
        incrementWordCount(word);
      }
    }
  }
  
  private void incrementWordCount(String word) {
    if (wordMap.containsKey(word)) {
      Integer count = (Integer) wordMap.get(word);
      int newCount = count.intValue() + 1;
      count = new Integer(newCount);
      wordMap.put(word, count);
    }
    else {
      wordMap.put(word, new Integer(1));
    }
  }

  public Map getTrimmedHistogram(double upperBound, double lowerBound) {
    //add all the words to a list
    ArrayList listOfWords = new ArrayList();
    Iterator itr = wordMap.keySet().iterator();
    while (itr.hasNext()) {
      Object word = itr.next();
      Integer count = (Integer) wordMap.get(word);
      listOfWords.add(new HistoWord(word.toString(), count));
    }
    
    //order the list then do the trimming
    Collections.sort(listOfWords); //sorted in ascending order  
    int listSize = listOfWords.size();
    
    double trimUpper = Math.floor(upperBound * listSize); //number of words to trim from the upper portion of the list
    int index = listSize;
    for(int i = 0; i < trimUpper; i++) {
      index--;
      HistoWord word = (HistoWord)listOfWords.get(index);
      wordMap.remove(word.text);
    }
    
    double trimLower = Math.floor(lowerBound * listSize); //number of words to trim from the lower portion of the list
    for(int i = 0; i < trimLower; i++) {
      HistoWord word = (HistoWord)listOfWords.get(i);
      wordMap.remove(word.text);
    }
    return wordMap;
  }

}